#include "servicemanager.h"
#include "dataaccessor.h"

#include <QCryptographicHash>
#include <QRandomGenerator>
#include <QVector>
#include "./entities/dbqueryresult.h"

ServiceManager ServiceManager::m_instance;

ServiceManager& ServiceManager::getInstance()
{
    return m_instance;
}

ServiceManager::ServiceManager(QObject* parent): QObject{parent}
{

}

ServiceManager::~ServiceManager()
{

}

void ServiceManager::logoutAllUsersNow()
{
    // 1. 下线全部用户
    if (!DataAccessor::updateAllUserOnlineStatus(false))
    {
        return;
    }
}

void ServiceManager::loginCheck(const qintptr descriptor, const LoginRequestMessage lrm)
{
    // 1. 优先检查用户是否存在
    QByteArray correctPassword;
    QString salt;
    int userId = lrm.getUserId().toInt();
    if (!DataAccessor::findPasswordAndSaltByUserId(userId, correctPassword, salt))
    {
        // 用户ID不存在，直接返回
        emit returnLoginCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_NO_USERID });
        return;
    }

    // 2. 验证密码
    QByteArray userInputPassword = hashPassword(lrm.getPassword(), salt);
    if (correctPassword != userInputPassword)
    {
        qDebug() << "密码不相等";
        qDebug() << correctPassword;
        qDebug() << userInputPassword;
        // 密码不正确，直接返回
        emit returnLoginCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_PWD_WRONG });
        return;
    }

    // 3. 密码正确，检查在线状态
    bool onlineStatus = false;
    if (!DataAccessor::findOnlineStatusByUserId(userId, onlineStatus))
    {
        // 获取在线状态失败，返回未知错误
        emit returnLoginCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_UNKNOWN_ERROR });
        return;
    }
    if (onlineStatus)
    {
        // 当前已在线，无法重复登录
        emit returnLoginCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_ALREADY_ONLINE });
        return;
    }

    // 4. 改变用户登录状态
    if (!DataAccessor::updateUserOnlineStatus(userId, true))
    {
        // 改变在线状态失败，返回未知错误
        emit returnLoginCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_UNKNOWN_ERROR });
        return;
    }

    // 5. 上述检查都通过，则登录成功
    emit returnLoginCheckResponse(descriptor, { JsonValue::STATUS_SUCCESS, JsonValue::REASON_SUCCESS });
    // 6. 告诉网络收发线程，某个套接字描述符对应的用户id，方便后续通过id转发
    emit addOnlineUser(descriptor, lrm.getUserId());

    return;
}

void ServiceManager::registerNewUser(const qintptr descriptor, const RegisterRequestMessage rrm)
{
    // 1. 检查邮箱是否重复
    bool isRegistered = false;
    if (!DataAccessor::findRegisteredUserByEmail(rrm.getEmail(), isRegistered))
    {
        // 返回结果无效，直接不允许注册（虽然很有可能是服务器的问题）
        emit returnRegisterCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_UNKNOWN_ERROR, "" });
        return;
    }
    if (isRegistered)
    {
        // 邮箱已经被注册过了
        emit returnRegisterCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_EMAIL_ALREADY_EXISTS, "" });
        return;
    }

    // 2. 无重复邮箱则注册新用户（静态表插值）
    QString salt = generateSalt();  // 生成盐值
    QByteArray hashedPassword = hashPassword(rrm.getPassword(), salt);  // 生成加盐哈希
    if (!DataAccessor::insertNewUserStaticInfo(rrm.getEmail(), rrm.getNickname(), hashedPassword, salt))
    {
        // 执行失败（未知原因）
        emit returnRegisterCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_UNKNOWN_ERROR, "" });
        return;
    }

    // 3. 注册新用户执行成功，可以开始获取新用户的Id
    int userId;
    if (!DataAccessor::findUserIdByEmail(rrm.getEmail(), userId))
    {
        // 执行失败（未知原因）
        emit returnRegisterCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_UNKNOWN_ERROR, "" });
        return;
    }

    // 4. 动态表插值
    if (!DataAccessor::insertNewUserDynamicInfo(userId))
    {
        // 执行失败（未知原因）
        emit returnRegisterCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_UNKNOWN_ERROR, "" });
        return;
    }

    // 5. 返回注册成功消息
    emit returnRegisterCheckResponse(descriptor, { JsonValue::STATUS_SUCCESS, JsonValue::REASON_SUCCESS, QString::number(userId) });
    return;

}

void ServiceManager::logout(const qintptr descriptor, const LogoutRequestMessage lrm)
{
    // 1. 更改在线状态
    int userId = lrm.getUserId().toInt();
    if (!DataAccessor::updateUserOnlineStatus(userId, false))
    {
        // 执行失败（未知原因）
        emit returnLogoutCheckResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_UNKNOWN_ERROR });
        return;
    }
    // 2. 返回登出成功消息
    emit returnLogoutCheckResponse(descriptor, { JsonValue::STATUS_SUCCESS, JsonValue::REASON_SUCCESS });
    // 3. 通知网络线程移出对应套接字
    emit userIdLogout(descriptor, lrm.getUserId());
}

void ServiceManager::searchNewUser(const qintptr descriptor, const SearchUserRequestMessage surm)
{
    // 1. 根据用户Id，寻找nickname
    int userId = surm.getUserId().toInt();
    QString nickname;
    if (!DataAccessor::findUserInfoByUserId(userId, nickname))
    {
        // 执行失败（未知原因）
        emit returnSearchUserResponse(descriptor, { JsonValue::STATUS_FAILURE, JsonValue::REASON_FAILURE_NO_USERID, "", "" });
        return;
    }
    // 2. 返回查找用户成功消息
    emit returnSearchUserResponse(descriptor, { JsonValue::STATUS_SUCCESS, JsonValue::REASON_SUCCESS, surm.getUserId(), nickname });
    return;
}



void ServiceManager::onlyLogoutUser(const qintptr descriptor, const QString userId)
{
    // qDebug() << "仅下线用户" << userId;
    // 更改在线状态
    if (!DataAccessor::updateUserOnlineStatus(userId.toInt(), false))
    {
        // 执行失败（未知原因）
        // qDebug() << "数据库同步失败";
        return;
    }
    // qDebug() << "数据库同步成功";
}

void ServiceManager::addFriendshipVerifyInfo(const qintptr descriptor, const ApplyFriendRequestMessageToServer afrmts)
{
    // 1. 在好友关系验证表中查询是否已经有过记录
    int userId = afrmts.getUserId().toInt();
    int friendId = afrmts.getFriendId().toInt();
    bool existed = false;
    if (!DataAccessor::findUnverifiedApplication(userId, friendId, existed))
    {
        qDebug() << "获取记录数量失败";
        return;
    }

    // 2. 判断进行插入还是更新
    if (!existed)   // 不存在
    {
        // 如果没有记录，在好友关系验证表中插入
        if (!DataAccessor::insertApplication(userId, friendId, afrmts.getAlias(), afrmts.getVerifyInfo()))
        {
            qDebug() << "好友关系验证表插入失败";
            return;
        }
    }
    else
    {
        // 如果有记录，在好友关系验证表中修改记录
        if (!DataAccessor::updateUnverifiedApplication(userId, friendId, afrmts.getAlias(), afrmts.getVerifyInfo()))
        {
            qDebug() << "好友关系验证表修改失败";

            return;
        }
    }

    return;
}

void ServiceManager::changeFriendshipStatus(const qintptr descriptor, const ApplyFriendResponseMessageToServer afrm)
{
    // 1. 在好友关系验证表中更改验证状态
    int status = 3; // 3代表审核被拒绝
    if (afrm.getStatus() == JsonValue::STATUS_ACCEPTED)
    {
        qDebug() << "审核通过";
        status = 2; // 2代表审核通过
    }
    int serverId = afrm.getId();
    if (!DataAccessor::updateFriendApplicationStatusById(serverId, status))
    {
        qDebug() << "根据记录id更新发送状态";
        return;
    }

    // 2. 申请没通过直接返回, 不继续向数据库添加好友关系
    if (status == 3)
    {
        return;
    }

    // 3. 执行到这里代表是好友：从好友关系验证表中取出申请人的备注等信息
    // 审核人是被申请好友的一方
    int verifierId;
    // 申请者是申请好友的一方
    int applicantId;
    // 这个是申请人对被申请人的备注
    QString alias;
    if (!DataAccessor::findUserIdsAndAliasByRecordId(serverId, applicantId, verifierId, alias))
    {
        qDebug() << "根据记录id寻找userId、friendId、alias失败";
        return;
    }


    // 4. 在好友关系表中记录好友关系（两条，双向好友）
    if (!DataAccessor::insertFriendship(applicantId, verifierId, alias))
    {
        qDebug() << "插入好友关系失败";
        return;
    }
    // 这个是被申请人对申请人的备注
    QString alias2 = afrm.getAlias();
    if (!DataAccessor::insertFriendship(verifierId, applicantId, alias2))
    {
        qDebug() << "插入好友关系失败";
        return;
    }
}

void ServiceManager::checkDataBuffer(const qintptr descriptor, const RequestBufferDataMessage rbdm)
{
    int userId = rbdm.getUserId().toInt();
    // 把用户下线时候收到的消息发过去
    qDebug() << "开始检查是否有需要发给当前登录用户的消息" << userId;
    checkOthersMessage(userId);
}

void ServiceManager::changeFriendApplicationStatus(const qintptr descriptor, const GetApplicationFromServer gafs)
{
    int id = gafs.getId();
    // 状态1代表服务器已经成功转发给客户端，但是此时客户端还没把审核结果发给服务器端
    if (!DataAccessor::updateFriendApplicationStatusById(id, 1))
    {
        return;
    }
}

// 改变好友申请结果的发送状态（审核结果转发给客户端后status从2或3变成4）
void ServiceManager::changeFriendApplicationResultSendStatus(const qintptr descriptor, const GetApplicationResultFromServer garfs)
{
    int id = garfs.getId();
    qDebug() << "客户端收到好友审核结果，发来确认消息";
    // 收到客户端的确认，服务器可以把数据库中的status2或3设置为4，代表客户端收到审核结果，至此，完成一个好友申请周期
    if (!DataAccessor::updateFriendApplicationStatusById(id, 4))
    {
        return;
    }
}

// 收到用户发给其好友的消息
void ServiceManager::saveChatMessage(const qintptr descriptor, const ChatMessageToServer cmts)
{
    // 1. 先把消息存入数据库
    QString senderId = cmts.getUserId();
    QString receiverId = cmts.getFriendId();
    qDebug() << "服务器收到用户发送消息给其好友";
    qDebug() << senderId << receiverId << cmts.getChatMessage();
    int senderId_int = cmts.getUserId().toInt();
    int receiverId_int = cmts.getFriendId().toInt();
    int uniqueId = -1;
    if (!DataAccessor::insertChatMsg(senderId_int, receiverId_int, cmts.getChatMessage(), uniqueId))
    {
        qDebug() << "数据库缓存用户消息失败";
        return;
    }
    // 2. 从数据库中取数据并尝试发给用户
    emit returnOtherChatMsg(receiverId,
        {senderId, cmts.getChatMessage(), QDateTime::currentDateTime().toString(Qt::ISODate), uniqueId});

}

// 改变好友消息的状态（消息缓存从0变1以代表接受者收到）
void ServiceManager::changeChatMsgStatus(const qintptr descriptor, const GetChatMessageFromServer gcmfs)
{
    int msgId = gcmfs.getId();
    if (!DataAccessor::updateChatMsgStatusById(msgId, 1))
    {
        qDebug() << "改变聊天消息缓存状态失败";
        return;
    }
}

// 试图转发客户端发起的视频通话请求
void ServiceManager::transpondVideoRequest(const qintptr descriptor, const VideoRequestToServer vrts)
{
    // 1. 查看当前用户是否在线，不在线直接转发对方离线
    int friendId = vrts.getFriendId().toInt();
    bool onlineStatus = false;
    if (!DataAccessor::findOnlineStatusByUserId(friendId, onlineStatus))
    {
        qDebug() << "查询" << friendId << "在线状态失败";
        return;
    }
    qDebug() << "转发对象" << friendId << "在线状态为：" << onlineStatus;
    if (!onlineStatus)
    {
        // 对方不在线，直接转发
        emit returnVideoResponseToRequestUser(vrts.getUserId(),
            {vrts.getUserId(), vrts.getFriendId(), JsonValue::STATUS_OFFLINE, ""});
        return;
    }
    // 2. 对方在线，转发给对方客户端VideoRequestToClient
    emit returnVideoRequestToResponseUser(vrts.getFriendId(),
                                          {vrts.getUserId(), vrts.getUserIp()});
}

// 转发客户端回应的视频通话请求回复
void ServiceManager::transpondVideoResponse(const qintptr descriptor, const VideoResponseToServer vrts)
{
    // 1. 把回应者的答复封装到回复消息体中
    emit returnVideoResponseToRequestUser(vrts.getRequestUserId(),
        {vrts.getRequestUserId(), vrts.getResponseUserId(), vrts.getStatus(), vrts.getResponseUserIp()});
}

// private:

void ServiceManager::checkOthersMessage(const int& userId)
{
    // 1. 检查是否有人申请user为好友
    checkNewFriendApplication(userId);

    // 2. 检查user向其他人申请的好友申请是否有结果
    checkFriendApplicationResult(userId);

    // 3. 检查是否有人给user发聊天消息
    checkNewChatMsg(userId);
}

// 检查是否有人申请user为好友
void ServiceManager::checkNewFriendApplication(const int& userId)
{
    QVector<NewFriendApplicationQueryResult> newFriendApplicationResult;
    if (!DataAccessor::findFriendApplicationsByUserId(userId, newFriendApplicationResult))
    {
        return;
    }
    // 把所有向user的好友申请转发给user
    for (auto queryResult: newFriendApplicationResult)
    {
        QString receiverId = QString::number(queryResult.receiverId);
        QString applicantId = QString::number(queryResult.applicantId);
        QString applyTime = queryResult.applyTime.toString(Qt::ISODate);
        emit returnOthersApplicationMessage(receiverId,
            { receiverId, applicantId, queryResult.nickname, queryResult.verifyInfo, applyTime, queryResult.id });
    }
}

// 检查user向其他人申请的好友申请是否有结果
void ServiceManager::checkFriendApplicationResult(const int& userId)
{
    qDebug() << "检查" << userId << "向其他人申请的好友申请是否有结果";
    QVector<FinishedFriendApplicationQueryResult> finishedFriendApplicationResult;
    if (!DataAccessor::findAllNewFriendApplicationResults(userId, finishedFriendApplicationResult))
    {
        return;
    }
    if (finishedFriendApplicationResult.size() == 0)
    {
        qDebug() << "没人完成对" << userId << "的审核";
    }
    // 对取出的结果进行解析和进一步封装
    for (auto queryResult: finishedFriendApplicationResult)
    {
        int friendId = queryResult.friendId;
        int serverId = queryResult.id;
        int status = queryResult.status;
        QString userId_str = QString::number(userId);
        QString friendId_str = QString::number(friendId);
        if (status == 3)    // 审核结果为拒绝
        {
            // 发送好友审核结果（拒绝版）
            emit returnFinishedApplicationResultMessage(userId_str,
                { friendId_str, "", JsonValue::STATUS_REJECTED, "", "", serverId} );
            // 不需要继续查询更多的好友关系
            continue;
        }
        // 审核结果为同意，还需要进一步查找
        FriendshipQueryResult friendshipResult;
        if (!DataAccessor::findFriendshipRecordBy2Id(userId, friendId, friendshipResult))
        {
            // 如果没有搜索到结果，不发送给客户端
            continue;
        }
        QString alias = friendshipResult.alias;
        QDateTime createTime = friendshipResult.createTime;
        QString nickname = friendshipResult.nickname;
        // 发送好友审核结果（同意版）
        emit returnFinishedApplicationResultMessage(userId_str,
            { friendId_str, nickname, JsonValue::STATUS_ACCEPTED, alias, createTime.toString(Qt::ISODate), serverId } );
    }
}


// 检查是否有人给user发聊天消息
void ServiceManager::checkNewChatMsg(const int& userId)
{
    qDebug() << "检查是否有人给" << userId << "发送消息";
    QVector<NewChatMsgQueryResult> results;
    if (!DataAccessor::findAllNewChatMsg(userId, results))
    {
        qDebug() << "检查" << userId << "失败";
        return;
    }
    if (!results.size())
    {
        qDebug() << "没人给" << userId << "发聊天消息";
        return;
    }
    QString receiverId_str = QString::number(userId);
    for (NewChatMsgQueryResult record: results)
    {
        emit returnOtherChatMsg(receiverId_str,
            {QString::number(record.senderId), record.msg, record.sendTime.toString(Qt::ISODate), record.id});
    }

}

QString ServiceManager::generateSalt(int length)
{
    const QString chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    QString salt;
    for (int i = 0; i < length; ++i) {
        int index = QRandomGenerator::global()->bounded(chars.size());
        salt.append(chars[index]);
    }
    return salt;
}

QByteArray ServiceManager::hashPassword(const QString &password, const QString &salt)
{
    QString combined = password + salt; // 将密码和盐值组合
    return QCryptographicHash::hash(combined.toUtf8(), QCryptographicHash::Sha256);
}

